package com.hk.blog.service.impl;

import com.hk.blog.domain.CategoryInfo;
import com.hk.blog.repository.jpa.CategoryInfoRepository;
import com.hk.blog.service.CategoryInfoService;
import com.hk.commons.JsonResult;
import com.hk.commons.query.Order;
import com.hk.commons.query.SortUtils;
import com.hk.commons.util.ObjectUtils;
import com.hk.commons.util.StringUtils;
import com.hk.core.authentication.api.SecurityContextUtils;
import com.hk.core.data.jpa.repository.BaseJpaRepository;
import com.hk.core.service.exception.ServiceException;
import com.hk.core.service.jpa.impl.JpaServiceImpl;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;

@Service
public class CategoryInfoServiceImpl extends JpaServiceImpl<CategoryInfo, Long> implements CategoryInfoService {

    private final CategoryInfoRepository categoryInfoRepository;

    public CategoryInfoServiceImpl(CategoryInfoRepository categoryInfoRepository) {
        this.categoryInfoRepository = categoryInfoRepository;
    }

    @Override
    protected ExampleMatcher ofExampleMatcher() {
        return super.ofExampleMatcher()
                .withMatcher("userId", ExampleMatcher.GenericPropertyMatchers.exact())
                .withMatcher("categoryName", ExampleMatcher.GenericPropertyMatchers.contains());
    }

    @Override
    protected BaseJpaRepository<CategoryInfo, Long> getBaseRepository() {
        return categoryInfoRepository;
    }

    @Override
    public boolean existsByCategoryName(Long userId, String categoryName) {
        categoryName = StringUtils.trimToEmpty(categoryName);
        return StringUtils.isNotEmpty(categoryName)
                && categoryInfoRepository.existsByUserIdAndCategoryName(userId, categoryName);
    }


    @Override
    @Transactional
    public CategoryInfo insert(CategoryInfo categoryInfo, Function<CategoryInfo, CategoryInfo> function) {
        CategoryInfo info = function.apply(categoryInfo);
        info.setUserId(SecurityContextUtils.getPrincipal().getUserId());
        info.setArticleNum(ObjectUtils.defaultIfNull(info.getArticleNum(), 0));
        if (existsByCategoryName(info.getUserId(), info.getCategoryName())) {
            throw new ServiceException(JsonResult.failure("已存在该类别"));
        }
        return categoryInfoRepository.save(info);
    }

    @Override
    @Transactional
    public CategoryInfo updateById(CategoryInfo categoryInfo, Function<CategoryInfo, CategoryInfo> function) {
        CategoryInfo info = function.apply(categoryInfo);
        info.setUserId(SecurityContextUtils.getPrincipal().getUserId());
        Optional<CategoryInfo> categoryInfoOptional = categoryInfoRepository.findByUserIdAndCategoryName(info.getUserId(),
                info.getCategoryName());
        if (categoryInfoOptional.isPresent() && !Objects.equals(categoryInfoOptional.get().getId(), info.getId())) {
            throw new ServiceException(JsonResult.failure("已存在该类别"));
        }
        info.setArticleNum(ObjectUtils.defaultIfNull(info.getArticleNum(), 0));
        return categoryInfoRepository.save(info);
    }

    @Override
    public List<CategoryInfo> findByUserId(Long userId, Order... orders) {
        return categoryInfoRepository.findByUserId(userId, SortUtils.toSort(orders));
    }

    @Override
    @Transactional
    public void subtractArticleNum(Long id, int articleNum) {
        categoryInfoRepository.subtractArticleNum(id, articleNum);
    }

    @Override
    @Transactional
    public void addArticleNum(Long id, int articleNum) {
        categoryInfoRepository.addArticleNum(id, articleNum);
    }
}
